/**
 * Widok dla analogowego wskaźnika
 */
package com.beans.indicator.view;

import com.beans.indicator.constans.IndicatorConstans;
import com.beans.indicator.model.IndicatorModel;
import java.awt.*;
import java.awt.event.ComponentEvent;
import java.awt.event.ComponentListener;
import java.awt.geom.AffineTransform;
import java.awt.geom.Rectangle2D;
import java.util.Observable;

/**
 *
 * @author Wojtek
 */
public class AnalogIndicatorView extends AbstractIndicatorView {

    //średnica tarczy wskaźnika
    private int size = 200;
    private int size2= 180;
    //współrzędne środka tarczy
    private int centerX = 100, centerY = 100;
    //odstęp pomiędzy tarczą a granicą komponentu
    //private int spacing = 0;
    private int spacing2 = 10;
    //punkt w którym ma zacząć malować podziałkę
    //0.25 PI czyli startujemy na godzinie 4:30 (0 na godzinie 6:00)
    private final static float offset = (float) (1 / 4.0 * Math.PI);
    private Color diodeOn = new Color(255, 0, 51);
    private Color diodeOff = new Color(153, 0, 51);
    protected AffineTransform hourTransform =
            AffineTransform.getRotateInstance(0, 0, 0);

    public AnalogIndicatorView(IndicatorModel model) {
        super(model);
        int ps = size;
        setPreferredSize(new Dimension(ps, ps));
        //dodajemy listener na zmianę rozmiaru komponentu
        this.addComponentListener(new ComponentListener() {

            public void componentResized(ComponentEvent e) {
                int w = getWidth();
                int h = getHeight();
                size = ((w < h) ? w : h);
                spacing2=size/20;
                size2=size-2*spacing2;
                centerX = size / 2;
                centerY = size / 2;
            }

            public void componentMoved(ComponentEvent e) {
            }

            public void componentShown(ComponentEvent e) {
            }

            public void componentHidden(ComponentEvent e) {
            }
        });
    }

    @Override
    protected void paintIndicatorFace(Graphics g) {
        Graphics2D g2 = getAAInstance(g);
        g2.setColor(foreground);
	g2.fillOval(0, 0, size, size);
        g2.setColor(background);
        g2.fillOval(spacing2, spacing2, size2, size2);
        g2.setColor(tickColor);
        for (int sec = 0; sec <= tickCount; sec++) {
            int ticStart;
            if (sec % largeTickInterval == 0) {
                ticStart = size2 / 2 - size2/8;
            } else {
                ticStart = size2 / 2 - size2/15;
            }
            drawRadius(g2, centerX, centerY, offset + getRadsPerTick() * sec, ticStart, size2 / 2);
        }

        g2.setColor(labelColor);
        drawLabels(g2);
    }

    @Override
    protected void paintDiode(Graphics g) {
        Graphics2D g2 = getAAInstance(g);
        Color c = null;
        if (model.isValueCritical()) {
            c = diodeOn;
        } else {
            c = diodeOff;
        }
        g2.setColor(c);
        g2.fillOval(centerX - size / 20, centerY + size / 10, size / 10, size / 10);
    }

    @Override
    protected void paintTitle(Graphics g) {
        Graphics2D g2 = getAAInstance(g);
        g2.setColor(titleColor);
        Font f = this.getFont();
        g2.setFont(new Font(f.getFontName(), Font.PLAIN, size / 10));
        FontMetrics fm = g.getFontMetrics();
        g2.drawString(title, size / 2 - fm.stringWidth(title) / 2, size / 2 + size / 3);
    }

    @Override
    protected void paintIndicator(Graphics g) {
        Graphics2D g2 = getAAInstance(g);
        g2.setColor(colorIndicator);
        //drawIndicator(g2, centerX, centerY, offset + (1.5 * Math.PI * (model.getMaxValue() - model.getValue())) / model.getMaxValue(), 0);
        drawIndicator(g2, centerX, centerY, offset+(1.5*Math.PI*(model.getValuesCount()-model.getAbsoluteValue(model.getValue())))/model.getValuesCount(), 0);
    }

    @Override
    protected void paintCritical(Graphics g) {
        Graphics2D g2 = getAAInstance(g);
        g2.setColor(criticalColor);
        g2.setStroke(new BasicStroke(2.0f));
        g2.fillArc(spacing2, spacing2, size2, size2, -45, 270*(model.getValuesCount()-model.getAbsoluteValue(model.getMaxCriticalValue()))/model.getValuesCount());
        g2.fillArc(spacing2, spacing2, size2, size2, 225, -270 + 270*(model.getValuesCount()-model.getAbsoluteValue(model.getMinCriticalValue()))/model.getValuesCount());
        int tmp = size2/2 - (size2 / 2 - size2/8)+1;
        g2.setComposite(AlphaComposite.getInstance(AlphaComposite.CLEAR, 0.0f));
        g2.fillOval(spacing2+tmp, spacing2+tmp, size2-2*tmp, size2-2*tmp);
    }

    private void drawRadius(Graphics g, int x, int y, double angle, int minRadius, int maxRadius) {
        float sin = (float) Math.sin(angle);
        float cos = (float) Math.cos(angle);
        int dxmin = (int) (minRadius * sin);
        int dymin = (int) (minRadius * cos);
        int dxmax = (int) (maxRadius * sin);
        int dymax = (int) (maxRadius * cos);
        g.drawLine(x + dxmin, y + dymin, x + dxmax, y + dymax);
    }

    private void drawLabels(Graphics2D g) {
        int maxRadius = size2/2;
        Font f = this.getFont();
        g.setFont(new Font(f.getFontName(), Font.PLAIN, size2 / 20));
        double angle = getRadsPerTick()*getLargeTickInterval();
        double angle2 = Math.toRadians(135);
        double val = model.getValuesCount() / (double)getTickCount();
        for (int tick = 0; tick <= getTickCount(); tick += getLargeTickInterval()) {
            int x2 = (int) (Math.cos(angle2) * (maxRadius - size2 / 6)) + maxRadius + size2 / 40 - g.getFont().getSize()/4;
            int y2 = (int) (Math.sin(angle2) * (maxRadius - size2 / 6)) + maxRadius + size2 / 15;
            g.drawString("" + (int)(tick*val+model.getMinValue()), x2, y2);
            angle2 += angle;
        }
    }

    private void drawIndicator(Graphics2D g, int x, int y, double angle, int minRadius) {
        float sin = (float) Math.sin(angle);
        float cos = (float) Math.cos(angle);
        int dxmin = (int) (minRadius * sin);
        int dymin = (int) (minRadius * cos);
        Point p1 = new Point((x + dxmin) - size2 / 30, y + dymin);
        Point p2 = new Point(x + 0, y + size2 / 2);
        Point p3 = new Point((x + dxmin) + size2 / 30, y + dymin);
        Point p4 = new Point(x + dxmin, (y + dymin) + size2 / 20);
        int[] xs = {p1.x, p2.x, p3.x, p4.x};
        int[] ys = {p1.y, p2.y, p3.y, p4.y};
        Polygon triangle = new Polygon(xs, ys, xs.length);
        hourTransform.setToRotation(-angle, x + dxmin, y + dymin);
        g.transform(hourTransform);
        g.fillPolygon(triangle);
    }

    private float getRadsPerTick() {
        return (float) (1.5 * Math.PI / tickCount);
    }
}
